package main.test.sparklingGraphAPI
import main.test.sparklingGraphAPI.LoadingGraph.ctx
import ml.sparkling.graph.api.loaders.GraphLoading.LoadGraph
import ml.sparkling.graph.api.operators.algorithms.community.CommunityDetection.ComponentID
import ml.sparkling.graph.api.operators.measures.VertexMeasureConfiguration
import ml.sparkling.graph.loaders.csv.GraphFromCsv.CSV
import ml.sparkling.graph.operators.measures.vertex.eigenvector.EigenvectorCentrality
import ml.sparkling.graph.operators.OperatorsDSL._
import org.apache.spark.graphx.{Graph, VertexRDD}
import org.apache.spark.sql.SparkSession
object EigenvecttorCentrality {
  def main(args: Array[String]): Unit = {

//    val spark: SparkSession = SparkSession.builder().getOrCreate()
//    import spark.implicits._


//    val filePath="data/your_graph_path.csv"
    val filePath="data/your_graph_pathf.csv"

    val graph: Graph[String, String] =LoadGraph.from(CSV(filePath)).load()
    // Eigenvector centrality
    /**
     * Eigenvector centrality measure give us information
     * about how  given node is important in network.
     * It is based on degree centrality. In here we have
     * more sophisticated version, where connections are not equal.
     *
     * E(x) = 1/lambda(sum(Aij xj))
     * Eigenvector centrality is more general approach than PageRank.
     * For further informations please refer to :
     * Finding and evaluating community structure in networks
     *
     * Library uses pregel operator in order to do computations.
     *
     */
      val graph2: Graph[Double, Int] =graph.mapEdges(x => 1.toInt).mapVertices((_, x)=>x.toDouble)

    val centralityGraph: Graph[Double, _] = graph2.eigenvectorCentrality()
    // Graph where each vertex is associated with its eigenvector centrality
    centralityGraph.edges.foreach(x=>println(x))
//    centralityGraph.triplets.map(e => if (e.dstAttr==))
    centralityGraph.vertices.foreach(x=>println(x))

    //  You can also compute eigenvector centrality for graph treated as undirected one

    val centralityGraph2: Graph[Double, _] = graph2.eigenvectorCentrality(VertexMeasureConfiguration(treatAsUndirected=true))

    centralityGraph2.edges.foreach(x=>println(x))
    centralityGraph2.vertices.foreach(x=>println(x))

    /**
     * Eigenvector centrality is implemented using iterative approach and Pregel operator.
     * Because of that you can provide your own computation stop predicate:
     */
    val eic: VertexRDD[Double] = EigenvectorCentrality
      .computeEigenvector(graph2,VertexMeasureConfiguration(), (iteration, oldValue, newValue)=>iteration<4).vertices
    eic.foreach(x=>println(x._1,x._2))



    // HIST
    /**
     * After measure computation, each vertex of graph will
     * have assigned two scores (hub,authority).
     * Where hub score is proportional to sum of authority score
     * of its neighbours, and authority
     * score is proportional to sum of hub score of its neighbours.
     * For further informations please refer to：
     * Hubs, authorities, and communities
     *
     *
     */
    //   Here you can see how to use measure

//    val centralityGraphHit: Graph[(Double,Double), _] = graph2.hits()
    val centralityGraphHit: Graph[(Double,Double), _] = graph2.hits(VertexMeasureConfiguration(treatAsUndirected=true))
    centralityGraphHit.vertices.foreach(println)

    // Graph where each vertex is associated
    // with its hits score (represented as a tuple (auth,hub):(Double,Double))


    // Degree Centrality
    /**
     *
     * Degree of a node is number of connections that
     * its has. When we have directed network, we can
     * distinguish indegree (input edges) and outdegree
     * (output edges). We can treate degree as a centrality
     * measure. Nodes with high degree can be assumed as
     * important.  Of course it depends on the sitution,
     * and interpretations can differ.
     *
     * More details referring to Carl Kingsford (2009). Modularity, PDF
     *
     * Method returns a tuple (outdegree, indegree):(Int,Int).
     * If computations will be done using treatAsUndirected, both value will be
     * equal.
     *
     */

    //    val centralityGraphWithDegree: Graph[(Int,Int), _] = graph2.degreeCentrality()
    val centralityGraphWithDegree: Graph[(Int,Int), _] = graph2.degreeCentrality(VertexMeasureConfiguration(treatAsUndirected=true))
    // Graph where each vertex is associated with its degree centrality in form of tuple (outdegree,indegree):(Int,Int)
    centralityGraphWithDegree.vertices.foreach(println)

    //  References:
    //
    //  [lecture]	Dr. Cecilia Mascolo, Social and Technological Network’Analysis PDF


    // Neighborhood Connectivity
    /**
     * Neighborhood connectivity is a measure based on degree centrality. Connectivity of a vertex is its degree. Neighborhood connectivity
     * is average connectivity of neighbours of given vertex.
     *
     * nc(x) = sum(|N(k)|),k belongs to N(x) / |N(x)
     *
     * N(x) is the set of neighbours of vertex x.
     * More information referring to
     * Maslov S, Sneppen K . Specificity and stability in topology of protein networks. Science 2002;296:910-913. HTML
     *
     */

    val centralityGraphRspNc: Graph[Double, _] = graph2.neighborhoodConnectivity()

    // Graph where each vertex is associated with its neighborhood connectivity
    centralityGraphRspNc.vertices.foreach(println)

    // Vertex Embeddedness
    /**
     * Is an average embededness of neighbours of given vertex.
     *
     */

    val centralityGraphVE: Graph[Double, _] = graph2.vertexEmbeddedness()
    // VertexMeasureConfiguration(treatAsUndirected=true)
    // Graph where each vertex is associated with its vertex embeddedness
    centralityGraphVE.vertices.foreach(println)


    // Local Clustering Coefficient
    /**
     * Local Clustering Coefficient for vertex tells us howe close its neighbors are. It’s number of existing connections in neighborhood
     * divided by number of all possible connections.
     */

    val centralityGraphLCC: Graph[Double, _] = graph2.localClustering(VertexMeasureConfiguration(treatAsUndirected=true))
    // Graph where each vertex is associated with its local clustering coefficient computed for undirected graph
    centralityGraphLCC.vertices.foreach(println)


    // Freeman’s network centrality
    /**
     * Freeman’s centrality tells us how heterogenous is degree centrality ammong vertices of network.
     * For start network, we will get a value 1.
     */


    val freemanCentrality: Double= graph2.freemanCentrality()
    // Freeman centrality value for graph, undirected graph
    println(freemanCentrality)


    // Modularity
    /**
    * Modularity measures strength of
    * division of a network into communities
    * (modules,clusters). Measures takes values
    * from range <−1,1>. Value close to 1 indicates strong community
    * structure. When Q=0 then the community
    * division is not better than random.
    *
    * Q=∑ki=1(eii−a2i)
    * Where k is number of communities,
    * eii is number of edges that has both ends in
    * community i and ai is number of edges with one end in community i
    */

    // attention Graph[ComponentID,_] can use this method
    val components2: Graph[ComponentID, Int] = graph2.PSCAN(epsilon = 0.6)
    val d: Double = components2.modularity()
    println(d)

    // Adamic/Adar
      /**
       * Adamic/Adar measures is defined as inverted sum of
       * degrees of common neighbours for given two vertices.
       */

//      val filePath2="data/your_graph_pathf.csv"
      val filePath2="src/main/test/Douban-dataset/data/edges.csv"

      val graph3: Graph[String, String] =LoadGraph.from(CSV(filePath2)).load()
//      val graph4: Graph[String, Int] = graph3.mapEdges(x => 1.toInt)
      // error!!!! 该函数和下面的函数不能用
      // java.lang.NoSuchMethodError: it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap.get(Ljava/lang/Long;)Ljava/lang/Object;
      val adamicAdarGraph: Graph[_, Double] = graph3.adamicAdar(treatAsUndirected=true )
      // Graph where each edge is associated with its Adamic/Adar measure
      adamicAdarGraph.edges.foreach(println(_))

    //    Common Neighbours
    /**
     * Common Neighbours measure is defined as
     * number of common neighbours of two given vertices.
     * CN(x,y)  = |N(x) intersection N(y)|
     * For memory consumption optimization, informations about neighbours are held in memory efficient implementations of
     * collections available in fastutil library.
     */

    val commonNeighbours: Graph[_, Int] = graph3.commonNeighbours(treatAsUndirected=true)
    // Graph where each edge is associated with number of common neighbours of vertices on edge
    commonNeighbours.edges.foreach(println)























  }

}
